﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity;
using FishServe.Client.Application.Manifest;
using System.Reflection;
using System.Diagnostics;

namespace FishServe.Client.Application
{
    internal class Module
    {
        private IUnityContainer _container;
        private ModuleLoader _moduleLoader;
        private ModuleManifestResolver _moduleManifestResolver;
        private ModuleManifest _moduleManifest;
        
        [Dependency]
        public ModuleLoader ModuleLoader
        {
            set 
            {
                if (_moduleLoader != value)
                {
                    _moduleLoader = value;
                    if (_moduleManifestResolver != null && _moduleLoader != null)
                        RegisterRegisteredTypes();
                }
            }

        }

        [Dependency]
        public ModuleManifestResolver ModuleManifestResolver
        {
            set 
            {
                if (_moduleManifestResolver != value)
                {
                    _moduleManifestResolver = value;
                    if (_moduleManifestResolver != null && _moduleLoader != null)
                        RegisterRegisteredTypes();
                }
            }
        }

        public IUnityContainer Container
        {
            get { return _container; }
        }

        public Module() : this(new UnityContainer())
        {}

        [InjectionConstructor]
        public Module([InjectChildContainer]IUnityContainer container)
        {
            _container = container;
            container.RegisterInstance<Module>(this);
        }

        protected void RegisterRegisteredTypes()
        {
            if( _moduleLoader == null )
                _moduleLoader = _container.Resolve<ModuleLoader>();

            if( _moduleManifestResolver == null )
                _moduleManifestResolver = _container.Resolve<ModuleManifestResolver>();

            _moduleManifest = _moduleManifestResolver.GetModuleManifest(this);

            foreach (ManifestRegisteredTypeInfo registeredTypeInfo in _moduleManifest.RegisteredTypes)
            {
                Assembly fromModule = _moduleLoader.LoadModule(registeredTypeInfo.FromTypeInfo);
                Assembly toModule = _moduleLoader.LoadModule(registeredTypeInfo.ToTypeInfo);

                Type fromType = fromModule.GetType(registeredTypeInfo.FromTypeInfo.TypeName);
                Type toType = toModule.GetType(registeredTypeInfo.ToTypeInfo.TypeName);

                if (registeredTypeInfo.Lifetime == RegisteredTypeLifetime.Singleton)
                    RegisterSingletonType(fromType, toType);
                else
                    RegisterType(fromType, toType);
                    
            }
        }

        protected void RegisterSingletonInstance<T>( T instance )
        {
            _container.RegisterInstance<T>(instance);
        }

        protected void RegisterSingletonType<TFrom, TTo>() where TTo : TFrom
        {
            _container.RegisterType<TFrom, TTo>(new ContainerControlledLifetimeManager());
        }

        protected void RegisterSingletonType(Type fromType, Type toType) 
        {
            _container.RegisterType( fromType, toType, new ContainerControlledLifetimeManager());
        }

        protected void RegisterType(Type fromType, Type toType)
        {
            _container.RegisterType(fromType, toType);
        }
    }
}
